/*
	Copyright (C) 2008 by Jean-FranÁois Geyelin
	jfgeyelin@gmail.com

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the
	Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/




#include "all.h"
#include "ThreadParameters.h"
#include "globals.h"
#include "DisplayString.h"
#include "SurfaceHandler.h"
#include "StreamHandler.h"
#include "Save.h"
#include "safeFileIO.h"
#include "DrawObject.h"
#include "drawButtonInMenu.h"
#include "handleEvents.h"
#include "readMap.h"
#include "downloadFileFromServer.h"
#include "copyFile.h"
#include "playMap.h"
#include "choseReplayMenu.h"
#include "wait.h"
#include "downloadAndPlayReplay.h"
#import "url.h"

#ifdef __WIN32__
#include <windows.h>
#include <shellapi.h>
#endif




int drawCompetitionMenu(std::string imageName, ScoreElement *scores, bool isObsolete,\
    std::string mapNumber, int fetching, bool failedToGetScore, SDL_Surface *destinationSurface, bool *fromScratch,\
    int offsetX, int offsetY, int mouseX, int mouseY, bool mouseJustGotPressed, bool mapIsUnlocked, int viewType, int time,\
    SplittedSurface *linkSurface) {

    mouseX-=offsetX;
    mouseY-=offsetY;


    char tempString[] = "more scores on                               ";
    //                  "more scores on http://killmario.game-host.org";
    int titleX = (destinationSurface->w-(strlen(tempString)*FONT_SPACING))/2;

    int linkX = titleX+13*8+2;
    int linkY = 63;
    bool linkIsHighlighted = (mouseX > linkX && mouseY > linkY-2 && mouseX < linkX+linkSurface->get(0)->w && mouseY < linkY+linkSurface->get(0)->h+2);


    if (*fromScratch) {

        SDL_Rect r;
        r.x = 0;
        r.y = 0;
        r.w = destinationSurface->w;
        r.h = destinationSurface->h;

        SDL_FillRect(destinationSurface, &r,SDL_MapRGB( screenSurface->format, 255,255,255 ));


        DisplayString::drawString3(mapNumber.c_str(), 20+((PREVIEW_WIDTH/2)-mapNumber.length()*FONT_SPACING)/2, 220, destinationSurface);



        SDL_Surface *preview = SurfaceHandler::loadImage( ("map_preview/"+imageName+".png"));


        if (!mapIsUnlocked) {
            SurfaceHandler::convertToGrayscale(preview);
        }

        SDL_Surface *resizedSurface = my_sge_transform_surface(preview,  0, 0,0.5,0.5,SGE_TAA|SGE_TSAFE);

        if (!mapIsUnlocked) {
            DisplayString::drawStringWithRedBorder("Locked", 20,30 , resizedSurface);
        }



        SurfaceHandler::drawSurface(resizedSurface, 20, 100, destinationSurface);
        SDL_FreeSurface(resizedSurface);
        SDL_FreeSurface(preview);

        SplittedSurface ss("medals.png",3);



        for (int i=0;i<NUMBER_OF_SCORES_PER_LEVEL;i++) {

            std::ostringstream o;
            o << scores[i].score;

            std::ostringstream o2;
            o2 << (i+1) << ".";
            DisplayString::drawString3(o2.str().c_str(), 275, 100+22*i, destinationSurface);
            DisplayString::drawString3(o.str().c_str(), 310, 100+22*i, destinationSurface);

            if (scores[i].name.length()<18) {
                DisplayString::drawString3(scores[i].name.c_str(), 360, 100+22*i, destinationSurface);
            }
            DisplayString::drawString3(scores[i].date.c_str(), 500, 100+22*i, destinationSurface);

            if (i<3 && scores[i].id != 0) {
                SurfaceHandler::drawSurface(ss.get(i), 296, 100+22*i, destinationSurface);
            }
        }


        int titleX2 = (destinationSurface->w-(11*LARGE_FONT_SPACING))/2;



		DisplayString::drawString("Competition", titleX2, 15, destinationSurface);






        DisplayString::drawString3(tempString, titleX, 60, destinationSurface);

        if (viewType==0)
        DisplayString::drawString3("* Best Scores *", 280, 80, destinationSurface);
        else
        DisplayString::drawString3("* Best Times *", 280, 80, destinationSurface);


        if (isObsolete) {
            DisplayString::drawString3("*THIS VERSION OF KM IS OLD*", 8, 270, destinationSurface);
            DisplayString::drawString3("Download a new version to", 15, 290, destinationSurface);
            DisplayString::drawString3("submit and watch replays.", 15, 305, destinationSurface);
        }
    }


    //s'occupe d'afficher et scroller les pseudo longs
    for (int i=0;i<NUMBER_OF_SCORES_PER_LEVEL;i++) {

        if (scores[i].name.length()>=18) {

            SDL_Rect r;
            r.x = 360;
            r.y = 100+22*i;
            r.w = FONT_SPACING*19;
            r.h = 14;
            SDL_FillRect(destinationSurface, &r,SDL_MapRGB( screenSurface->format, 255,255,255 ));

            std::string name = scores[i].name;

			int n = (name.length()-18+5);
			int t = (time/4)%(n*2);

			int start = t%n;
			if (t<n) {
				if (start>=name.length()-18) {
					start = name.length()-18;
				}
			}
			else {
				if (start>=name.length()-18) {
					start = 0;
				}
				else
				{
					start = name.length()-18-start;
				}
			}
            std::string tempName = name.substr(start, 18);
            DisplayString::drawString3(tempName.c_str(), 360, 100+22*i, destinationSurface);
        }
    }





    int returnValue = 0;


    //efface la string "fetching scores" (et surtout efface les pointillÈs pour leurs animation)
    SDL_Rect r;
    r.x = 300;
    r.y = 330;
    r.w = 210;
    r.h = 16;
    SDL_FillRect(destinationSurface, &r,SDL_MapRGB( screenSurface->format, 255,255,255 ));

    //affiche le lien

    SurfaceHandler::drawSurface(linkSurface->get((linkIsHighlighted?0:1)), linkX, linkY, destinationSurface);
    returnValue |= (linkIsHighlighted?DOWNLOAD_KM_CMB:0);


    if (!failedToGetScore) {

        if (fetching>0) {//affiche "fetching scores..."...
            fetching/=10;
            //int w = destinationSurface->w;
            std::string str = "Updating scores";
            fetching %= 3;
            fetching++;
            while(fetching--)
            str+=".";
            DisplayString::drawString3(str.c_str(), 450, 325, destinationSurface);

            SDL_Rect r;
            r.x = 360;
            r.y = 325;
            r.w = 80;
            r.h = 20;
            drawButtonInMenu(r, "Refresh", destinationSurface, buttonsInactiveColor, buttonsInactiveBorderColor);
        }
        else {
            returnValue |= drawButtonInMenu(mouseX, mouseY, 360, 325, 80 , 20 , "Refresh", destinationSurface,0,REFRESH_CMB);
        }
    }
    else {
        DisplayString::drawString3("Failed to download scores", 400, 330, destinationSurface);
    }




    if (mapIsUnlocked && !isObsolete) {
        for (int i=0;i<NUMBER_OF_SCORES_PER_LEVEL;i++) {
            if (scores[i].id != 0)
            returnValue |= drawButtonInMenu(mouseX, mouseY, 215, 98+22*i, 50 , 20 , "watch", destinationSurface,0,100+i);
        }
    }


    returnValue |= drawButtonInMenu(mouseX, mouseY, 20, 220, 40 , 20 , "<<", destinationSurface,0,PREVIOUS_CMB);
    returnValue |= drawButtonInMenu(mouseX, mouseY, 20+(PREVIEW_WIDTH/2)-40, 220, 40 , 20 , ">>", destinationSurface,0,NEXT_CMB);

    if (!isObsolete)
    returnValue |= drawButtonInMenu(mouseX, mouseY, 20+(PREVIEW_WIDTH/2-120)/2, 280, 120 , 20 , "Chose replay", destinationSurface,0,CHOSE_REPLAY_CMB);
    /*else
    returnValue |= drawButtonInMenu(mouseX, mouseY, 40, 330, 120 , 20 , "Download", destinationSurface,0,DOWNLOAD_KM_CMB);*/

    if (viewType==0)
    returnValue |=  drawButtonInMenu(mouseX, mouseY, 215, 325, 130 , 20 , "View best times", destinationSurface,0,SWITCH_SCORES_CMB);
    else
    returnValue |=  drawButtonInMenu(mouseX, mouseY, 215, 325, 130 , 20 , "View best scores", destinationSurface,0,SWITCH_SCORES_CMB);


    if (mapIsUnlocked && !isObsolete) {
        //returnValue |= drawButtonInMenu(mouseX, mouseY, 50, 250, (PREVIEW_WIDTH/2)-60 , 20 , "Play", destinationSurface,0,PLAY_CMB);

        returnValue |= drawButtonInMenu(mouseX, mouseY, 20+(PREVIEW_WIDTH/2-80)/2, 250, 80 , 20 , "Play", destinationSurface,0,PLAY_CMB);
    }

    returnValue |= drawButtonInMenu(mouseX, mouseY, 20+(destinationSurface->w-180)/2, 355, 120 , 20 , "Back", destinationSurface,1,BACK_CMB);

    if (*fromScratch) {
        *fromScratch = false;
        Uint8 *keystates;
        SDL_Flip( screenSurface );

        do  {
            handleEvents();
            keystates = SDL_GetKeyState( NULL );
            SDL_Delay(19);
        } while (keystates[ SDLK_LEFT ] || keystates[ SDLK_RIGHT ]);
    }


    if (mouseJustGotPressed) {
        /*while (SDL_GetMouseState(&mouseX,&mouseY)&SDL_BUTTON(1)) {
            SDL_Delay(5);
            handleEvents();
        }*/
        return returnValue;
    }
    return -returnValue;
}



#define UPDATING_SCORES 0
#define UPDATING_JUST_FINISHED 1
#define NOT_UPDATING 2
#define UPDATING_FAILED 3


#define KM_VERSION  3


void getScoresFromFile(ScoreElement *scores, int n, bool *isObsolete) {
    FILE *f;
    f = fopen_safe("save/scores.txt","rb");

    if (!f) {
        TEST_EXECUTION()
        for (int i=0;i<n;i++,scores++) {
            scores->id=0;
            scores->date="--";
            scores->score=0;
            scores->name="--";
        }
        *isObsolete = false;
        return;
    }

    long version;

    StreamHandler::readLong(f,&version);

    if (version != KM_VERSION) {
        *isObsolete = true;
    }
    else {
        *isObsolete = false;
    }


    TEST_EXECUTION()
    for (int i=0;i<n;i++,scores++) {
        if (!StreamHandler::readLong(f,&(scores->id)))
        break;
        if (!StreamHandler::readString(f,&(scores->date)))
        break;
        if (!StreamHandler::readLong(f,&(scores->score)))
        break;
        if (!StreamHandler::readString(f,&(scores->name)))
        break;
    }
    fclose(f);
}




void startCompetitionMenu(void) {
    KeyPressed keyPressed;


    SurfaceHandler::colorScreen(255,255,255);
	std::string maps[MAX_NUMBER_OF_MAPS];
    TEST_EXECUTION()
	int numberOfMaps = readMap(maps);

    TEST_EXECUTION()

	int numberOfMapsUnlocked;
    {
        Save s;
        int n=0;
        for (int slot=0;slot<NUMBER_OF_SLOTS;slot++) {
            s.readSave(slot);
            if (s.getNumberOfLevels()>n) {
                n = s.getNumberOfLevels();
            }
        }
        numberOfMapsUnlocked = n;
    }

    TEST_EXECUTION()


    int returnValue = 1;
    int previousReturnValue = 1;

    std::string imageName;


#ifdef _MSVC_
    /** workaround Onur's incompetence */
    ScoreElement scores[14*NUMBER_OF_SCORES_PER_LEVEL*2];
#else
    ScoreElement scores[numberOfMaps*NUMBER_OF_SCORES_PER_LEVEL*2];
#endif


    int mapNumber=1;
    std::string mapNumberString;
    SDL_Surface *temp = SDL_CreateRGBSurface(SDL_HWSURFACE, 580, 400, 32, bmask, gmask, rmask, amask);
    int offsetX = (screenSurface->w - temp->w)/2;
    int offsetY = (screenSurface->h - temp->h)/2;
    int mouseX;
    int mouseY;
    bool mouseIsPressed;
    bool mouseWasPressed = true;
    bool mouseJustGotPressed;
    int viewType = 0;
    int time = 0;
    Uint32 lastFrameMS = 0;
    int fetching = 1;
    int updatingScores = UPDATING_SCORES;
    bool fromScratch = true;
    bool kmVersionIsObsolete = false;
    SplittedSurface linkSurface("link.png",2);

    TEST_EXECUTION()

    getScoresFromFile(scores, numberOfMaps*NUMBER_OF_SCORES_PER_LEVEL*2, &kmVersionIsObsolete);

    SDL_Thread *thread;

    TEST_EXECUTION()

    ThreadParameters *tp = new ThreadParameters(URL_OF_SERVER"/AllTheScores","save/scores_temp.txt");


    thread = SDL_CreateThread(getFileFromServerThread, tp);


    TEST_EXECUTION()




    while (!quit) {



        keyPressed.readKeys();


        if (fetching>0) {
            fetching++;
        }
        else
        {
            fetching = -10;
        }


        if (updatingScores == UPDATING_SCORES) {

            if (tp->getFileIsDownloaded()) {
                updatingScores = UPDATING_JUST_FINISHED;
                if (tp->getThereHasBeenAnError()) {
                    updatingScores = UPDATING_FAILED;
                }
            }

            if (updatingScores == UPDATING_JUST_FINISHED) {
                copyFile("save/scores_temp.txt","save/scores.txt");\
                remove_safe("save/scores_temp.txt");
            }
        }

        if (updatingScores == UPDATING_JUST_FINISHED) {
            updatingScores = NOT_UPDATING;
            fetching = -10;
            getScoresFromFile(scores, numberOfMaps*NUMBER_OF_SCORES_PER_LEVEL*2,&kmVersionIsObsolete);
            fromScratch = true;
        }


        if (keyPressed.left)
        returnValue = PREVIOUS_CMB;
        if (keyPressed.right)
        returnValue = NEXT_CMB;
        if (keyPressed.action || keyPressed.letterIsPressed('p'))
        returnValue = PLAY_CMB;
        if (keyPressed.letterIsPressed('b'))
        quit = true;
        if (keyPressed.up || keyPressed.down || keyPressed.letterIsPressed('v')) {
            returnValue = SWITCH_SCORES_CMB;
            //keyPressed.readKeys();
            //handleEvents();
            while (keyPressed.up || keyPressed.down || keyPressed.letterIsPressed('v')) {
                SDL_Delay(19);
                keyPressed.readKeys();
                handleEvents();
            }
        }


        if (returnValue != 0) {

            switch (returnValue) {
                case NEXT_CMB:
                    mapNumber++;
                    break;
                case PREVIOUS_CMB:
                    mapNumber--;
                    break;
                case BACK_CMB:
                    return;
                case DOWNLOAD_KM_CMB:

                    char buffer[512];


#ifdef __WIN32__
                    sprintf(buffer,"http://killmario.game-host.org/index.php?p=scores#%c%i",(viewType==0?'a':'b'),mapNumber);
                    ShellExecute(0, "open", buffer, NULL, ".", SW_SHOWNORMAL);
#endif
#ifdef __APPLE__
                    sprintf(buffer,"open http://killmario.game-host.org/index.php?p=scores#%c%i",(viewType==0?'a':'b'),mapNumber);
					system(buffer);
#endif
                    break;
                case PLAY_CMB:
                    TEST_EXECUTION()
                    playMap(maps[mapNumber], NULL, NULL, true);
                    TEST_EXECUTION()
                    offsetX = (screenSurface->w - temp->w)/2;//update offset in case of a resolution change
                    offsetY = (screenSurface->h - temp->h)/2;

                    TEST_EXECUTION()
                    quit = false;
                    SurfaceHandler::colorScreen(255,255,255);

                    returnValue = 0;

                    break;
                case CHOSE_REPLAY_CMB:
                    choseReplayMenu();
                    waitForKeyRelease();
                    quit = false;
                    break;
                case REFRESH_CMB:
                    if (tp->getFileIsDownloaded() == true) {
                        fetching = 1;
                        updatingScores = UPDATING_SCORES;
                        delete tp;
                        tp = new ThreadParameters(URL_OF_SERVER"/AllTheScores","save/scores_temp.txt");
                        thread = SDL_CreateThread(getFileFromServerThread, tp);
                    }
                    break;
                case SWITCH_SCORES_CMB:
                    viewType =! viewType;
                    getScoresFromFile(scores, numberOfMaps*NUMBER_OF_SCORES_PER_LEVEL*2,&kmVersionIsObsolete);
                    fromScratch = true;
                    break;

                default:
                    if (returnValue>=100) {
                        downloadAndPlayReplay(scores[mapNumber*NUMBER_OF_SCORES_PER_LEVEL+(returnValue-100)+(viewType==1?numberOfMaps*NUMBER_OF_SCORES_PER_LEVEL:0)].id);
                        SurfaceHandler::colorScreen(255,255,255);
                        quit = false;
                    }
                    break;
            }

            if (mapNumber<0)
            mapNumber+=numberOfMaps;
            if (mapNumber>=numberOfMaps)
            mapNumber-=numberOfMaps;


            std::ostringstream o;
            o << mapNumber+1 << "/" << numberOfMaps;

            mapNumberString = o.str();

            imageName = maps[mapNumber];
            fromScratch = true;

        }



        mouseIsPressed = SDL_GetMouseState(&mouseX,&mouseY)&SDL_BUTTON(1);
        mouseJustGotPressed = !mouseWasPressed && mouseIsPressed;
        mouseWasPressed = mouseIsPressed;


       // fromScratch = false;


        returnValue = drawCompetitionMenu(imageName,&scores[mapNumber*NUMBER_OF_SCORES_PER_LEVEL+(viewType==1?numberOfMaps*NUMBER_OF_SCORES_PER_LEVEL:0)],\
        kmVersionIsObsolete, mapNumberString, fetching,  updatingScores == UPDATING_FAILED, temp,&fromScratch,\
        offsetX, offsetY, mouseX, mouseY, mouseJustGotPressed,mapNumber<numberOfMapsUnlocked,viewType,time,&linkSurface);
        time++;
        if (returnValue <= 0) {
            if (returnValue != previousReturnValue) {
                if (returnValue != 0)
                allSounds->play("menu");
                previousReturnValue = returnValue;
            }
        }

        SurfaceHandler::drawSurface(temp, offsetX, offsetY, screenSurface);

        if (mapNumber>numberOfMapsUnlocked) {

        }else {
            //numberOfMapsUnlocked

        }

        SDL_Flip( screenSurface );

		//SDL_Delay(10);

        while ((SDL_GetTicks() - lastFrameMS) < 30) {
            SDL_Delay(1);
        }
        lastFrameMS = SDL_GetTicks();


		handleEvents();



    }


    if (tp->getFileIsDownloaded() == false)
    SDL_KillThread(thread);
    delete tp;


    SDL_FreeSurface(temp);

    quit = false;

}


#undef UPDATING_SCORES
#undef UPDATING_JUST_FINISHED
#undef NOT_UPDATING
#undef UPDATING_FAILED
